//
//  NetworkView.m
//  AccSim
//
//  Created by Otto Chrons on 9/25/08.
//  Copyright 2008 Enzymia Ltd.. All rights reserved.
//

#import "NetworkView.h"
#import "AccelerationInfo.h"
#include <unistd.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <errno.h>

#include <ifaddrs.h> 
#include <arpa/inet.h>

// default UDP port
#define kAccelerometerSimulationPort 10552

// the amount of vertical shift upwards keep the text field in view as the keyboard appears
#define kOFFSET_FOR_KEYBOARD					100.0

// the duration of the animation for the view shift
#define kVerticalOffsetAnimationDuration		0.30

@interface NetworkView()

// called on 'finger-down', delegates to up scale tween [animateFirstTouchAtPoint]
-(void)dispatchFirstTouchAtPoint:(CGPoint)touchPoint forEvent:(UIEvent *)event;

// tween scales the btn up while touch is true
-(void)animateFirstTouchAtPoint:(CGPoint)touchPoint forView:(UIImageView *)theView;

// called on 'finger-up', delegates to dn scale tween [animateView]
-(void)dispatchTouchEndEvent:(UIView *)theView toPosition:(CGPoint)position;

// tweens the btn back down to 100%
-(void)animateView:(UIView *)theView toPosition:(CGPoint) thePosition;
@end


@implementation NetworkView

// duration consts
#define BTN_PRESS_INTRO_DUR 0.10
#define BTN_PRESS_OUTRO_DUR 0.15

// generate the three btns
@synthesize firstPieceView;
@synthesize secondPieceView;
@synthesize thirdPieceView;

// Override initWithNibName:bundle: to load the view using a nib file then perform additional customization that is not appropriate for viewDidLoad.
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
    if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) {
		
		// default unicast address is localhost
		ipAddr_send = @"127.0.0.1";
		// start in network disabled mode
		networkEnabled = YES;
	
		// listen to updates from AccelerometerViewControl
		[[NSNotificationCenter defaultCenter] addObserver:self 
												 selector:@selector(accelerationUpdate:) 
													 name:@"AccelerationUpdate" 
												   object:nil];
		// create socket
		udpSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
		// init in broadcast mode
		int broadcast = 1;
		setsockopt(udpSocket, SOL_SOCKET, SO_BROADCAST, &broadcast, sizeof(int));

		memset((char *) &targetAddress, 0, sizeof(targetAddress));
		targetAddress.sin_family = AF_INET;
		// broadcast address 255.255.255.255
		// TODO: figure out device IP address and netmask, produce a subnet broadcast address
		targetAddress.sin_addr.s_addr = htonl(0xFFFFFFFF);
		targetAddress.sin_port = htons(kAccelerometerSimulationPort);
		targetAddress.sin_len = sizeof(targetAddress);
		
		//ipAddr_from = getIPAddress();
    }
    return self;
}


- (IBAction)onLeftBtn:(id)sender {
	NSLog(@"<[[: onLeftBtn :]]>");
	
	// only process is network is enabled and socket initialized OK
	if (networkEnabled && udpSocket != -1) {
		const char *msg = [[NSString stringWithFormat:@"<ACCELR [dev_id:ANDVARI,frAddr:%s,toAddr:%s,ts:1234] {x:1,y:0,z:0}>",[ipAddr_send UTF8String],[ipAddr_send UTF8String]] UTF8String];
		NSLog(@"Dispatching BSD Packet: %s", msg);
	
		int error = sendto(udpSocket, msg, strlen(msg), 0, (struct sockaddr*)&targetAddress, sizeof(targetAddress));
		if (error < 0) {
			NSLog(@"Socket error %d", errno);
		}
	}
}

- (IBAction)onMiddleBtn:(id)sender {
	NSLog(@"<[[: onMiddleBtn :]]>");
	
	// only process is network is enabled and socket initialized OK
	if (networkEnabled && udpSocket != -1) {
		const char *msg = [[NSString stringWithFormat:@"<ACCELR [dev_id:ANDVARI,frAddr:%s,toAddr:%s,ts:1234] {x:0,y:1,z:0}>",[ipAddr_send UTF8String],[ipAddr_send UTF8String]] UTF8String];
		NSLog(@"Dispatching BSD Packet: %s", msg);
	
		int error = sendto(udpSocket, msg, strlen(msg), 0, (struct sockaddr*)&targetAddress, sizeof(targetAddress));
		if (error < 0) {
			NSLog(@"Socket error %d", errno);
		}
	}
}

- (IBAction)onRightBtn:(id)sender {
	NSLog(@"<[[: onRightBtn :]]>");
	
	// only process is network is enabled and socket initialized OK
	if (networkEnabled && udpSocket != -1) {
		const char *msg = [[NSString stringWithFormat:@"<ACCELR [dev_id:ANDVARI,frAddr:%s,toAddr:%s,ts:1234] {x:0,y:0,z:1}>",[ipAddr_send UTF8String],[ipAddr_send UTF8String]] UTF8String];
		NSLog(@"Dispatching BSD Packet: %s", msg);
	
		int error = sendto(udpSocket, msg, strlen(msg), 0, (struct sockaddr*)&targetAddress, sizeof(targetAddress));
		
		if (error < 0) {
		NSLog(@"Socket error %d", errno);
		}
	}
}

// notification handler for acceleration updates
- (void)accelerationUpdate:(NSNotification*)notification {
	AccelerationInfo* info = (AccelerationInfo*)[notification object];
	
	/*
	// only process is network is enabled and socket initialized OK
	if( networkEnabled && udpSocket != -1 )
	{
		// create UDP packet as formatted string
		// "ACC: <deviceid>,<timestamp>,<x>,<y>,<z>"
				
		//NSString frmtDatagram = @"<GYRO: (%1.3f,%1.3f,%1.3f)>";
		//NSString frmtDatagram = @"<ACCELR [%s,%.3f] {%1.3f,%1.3f,%1.3f}>";
		
		//ORG__ const char *msg = [[NSString stringWithFormat:@"ACC: %s,%.3f,%1.3f,%1.3f,%1.3f\n",[info.deviceID UTF8String],info.absTime,info.x,info.y,info.z] UTF8String];
		
		const char *msg = [[NSString stringWithFormat:@"<ACCELR [dev_id:%s,frAddr:%s,toAddr:%s,ts:%.2f] {x:%1.3f,y:%1.3f,z:%1.3f}>",[info.deviceID UTF8String],[ipAddr_send UTF8String],[ipAddr_send UTF8String],info.absTime,info.x,info.y,info.z] UTF8String];
		NSLog(@"Dispatching BSD Packet: %s", msg);
		
		int error = sendto(udpSocket, msg, strlen(msg), 0, (struct sockaddr*)&targetAddress, sizeof(targetAddress));
		if (error < 0) {
			NSLog(@"Socket error %d", errno);
		}
	}
	*/
}

/*
// Handles the start of a touch [finger-down]
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
	//~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~~*~._
	NSLog(@"<[[: touchesBegan :]]>");
	
	NSUInteger touchCount = 0;
	
	UITouch *anyTouch = [touches anyObject];
	
	NSLog(@"1st (Y) = [%s]", firstPieceView);
	NSLog(@"2st (B) = [%s]", secondPieceView);
	NSLog(@"3st (R) = [%s]", thirdPieceView);
	NSLog(@"Any Touch = [%s]", anyTouch);
	
	 for (UITouch *touch in touches) {
		
		NSLog(@"Touches[%f] = [%s]", touchCount, touch);
		touchCount++;
		 
		// Send to the dispatch method
		//[self dispatchFirstTouchAtPoint:[touch locationInView:self] forEvent:nil];
	}	
	
}//]~*~~*~~*~~*~~*~~*~~*~~*~~·¯


// 
// √ to see which btn the pt is in & calls dispatch method to exe intro animation.
-(void)dispatchFirstTouchAtPoint:(CGPoint)touchPoint forEvent:(UIEvent *)event {
	//~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~~*~._
	NSLog(@"<[[: dispatchFirstTouchAtPoint :]]>");
	
	
	if (CGRectContainsPoint([firstPieceView frame], touchPoint))
		[self animateFirstTouchAtPoint:touchPoint forView:firstPieceView];
	
	
	if (CGRectContainsPoint([secondPieceView frame], touchPoint))
		[self animateFirstTouchAtPoint:touchPoint forView:secondPieceView];
	
	
	if (CGRectContainsPoint([thirdPieceView frame], touchPoint))
		[self animateFirstTouchAtPoint:touchPoint forView:thirdPieceView];
	
}//]~*~~*~~*~~*~~*~~*~~*~~*~~·¯


// Handles the end of a touch event ['finger-up'].
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
	//~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~~*~._
	NSLog(@"<[[: touchesEnded :]]>");
	
	/*
	// loop thru all touch object
	for (UITouch *touch in touches) {
		
		// Sends to the dispatch method, which will make sure the appropriate subview is acted upon
		[self dispatchTouchEndEvent:[touch view] toPosition:[touch locationInView:self]];
	}
	
}//]~*~~*~~*~~*~~*~~*~~*~~*~~·¯


// Checks to see which view, or views,  the point is in and then calls a method to perform the closing animation,
// which is to return the piece to its original size, as if it is being put down by the user.
-(void)dispatchTouchEndEvent:(UIView *)theView toPosition:(CGPoint)position {
	//~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~~*~._
	NSLog(@"<[[: dispatchTouchEndEvent :]]>");
	
	NSString *btnID = @"BTN_";
	
	// leftmost / btn 1
	if (CGRectContainsPoint([firstPieceView frame], position)) {
		
		btnID = [[btnID stringByAppendingString:@"01"] UTF8String];
		[self animateView:firstPieceView toPosition: position];
	}
	
	// middle / btn 2
	if (CGRectContainsPoint([secondPieceView frame], position)) {
		
		btnID = [[btnID stringByAppendingString:@"02"] UTF8String];
		[self animateView:secondPieceView toPosition: position];
	}
	
	// rightmost / btn 3
	if (CGRectContainsPoint([thirdPieceView frame], position)) {
		
		btnID = [[btnID stringByAppendingString:@"03"] UTF8String];
		[self animateView:thirdPieceView toPosition: position];
	}
	
	NSLog(@"Tapped btn was #[%s]", btnID);
	
}//]~*~~*~~*~~*~~*~~*~~*~~*~~·¯


-(void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
	//~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~~*~._
	NSLog(@"<[[: touchesCancelled :]]>");
	
	// Enumerates through all touch object
	for (UITouch *touch in touches) {
		
		// Sends to the dispatch method, which will make sure the appropriate subview is acted upon
		[self dispatchTouchEndEvent:[touch view] toPosition:[touch locationInView:self]];
	}
	
}//]~*~~*~~*~~*~~*~~*~~*~~*~~·¯

#pragma mark -
#pragma mark === Animating subviews ===
#pragma mark

// Scales up the tapped view
-(void)animateFirstTouchAtPoint:(CGPoint)touchPoint forView:(UIImageView *)theView {
	//~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~~*~._
	NSLog(@"<[[: animateFirstTouchAtPoint :]]>");
	
	// Pulse the view by scaling up, then move the view to under the finger.
	[UIView beginAnimations:nil context:nil];
	[UIView setAnimationDuration:BTN_PRESS_INTRO_DUR];
	
	theView.transform = CGAffineTransformMakeScale(1.5, 1.5);
	[UIView commitAnimations];
	
}//]~*~~*~~*~~*~~*~~*~~*~~*~~·¯


// Scales back down the corresponding view to 100%. 
-(void)animateView:(UIView *)theView toPosition:(CGPoint)thePosition {
	//~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~~*~._
	NSLog(@"<[[: animateView :]]>");
	
	[UIView beginAnimations:nil context:NULL];
	[UIView setAnimationDuration:BTN_PRESS_OUTRO_DUR];
	
	// Set the transform back to the identity, thus undoing the previous scaling effect.
	theView.transform = CGAffineTransformIdentity;
	[UIView commitAnimations];
	
}//]~*~~*~~*~~*~~*~~*~~*~~*~~·¯
*/

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
    // Return YES for supported orientations
    return (interfaceOrientation == UIInterfaceOrientationPortrait);
}


- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning]; // Releases the view if it doesn't have a superview
    // Release anything that's not essential, such as cached data
}


- (void)dealloc {
	
	// Release each of the subviews
	[firstPieceView release];
	[secondPieceView release];
	[thirdPieceView release];
	
    [super dealloc];
}


@end
